﻿using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;
using Image = System.Drawing.Image;

namespace SvgViewer.Utilities;

internal static class ImageUtility
{
    /// <summary>
    /// XAML 内容转换为控件
    /// </summary>
    /// <param name="xaml">要转换的内容</param>
    /// <param name="throwError">是否抛出异常</param>
    /// <returns></returns>
    public static FrameworkElement XamlToControl(string xaml, bool throwError = false)
    {
        FrameworkElement element = null;
        if (!string.IsNullOrEmpty(xaml))
        {
            try
            {
                using (var stringReader = new StringReader(xaml))
                {
                    using (var xmlReader = XmlReader.Create(stringReader))
                    {
                        element = (FrameworkElement)XamlReader.Load(xmlReader);
                    }
                }
            }
            catch
            {
                if (throwError)
                {
                    throw;
                }
            }
        }

        return element;
    }

#region 保存为图片

    public static void SaveImage(FrameworkElement control, string filePath)
    {
        if (control == null)
        {
            return;
        }

        var ext = Path.GetExtension(filePath).ToLowerInvariant();
        switch (ext)
        {
            case ".ico":
                SaveToIcon(control, filePath);
                break;
            default:
                SaveToImage(control, filePath, ext);
                break;
        }
    }

    private static void SaveToIcon(FrameworkElement control, string filePath)
    {
        var rect   = new Rect(control.RenderSize);
        var visual = new DrawingVisual();
        using (var dc = visual.RenderOpen())
        {
            dc.DrawRectangle(new VisualBrush(control), null, rect);
        }

        var bitmap = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
        bitmap.Render(visual);
        bitmap.Freeze();
        var encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmap));
        using (var stream = new MemoryStream())
        {
            encoder.Save(stream);
            var buffer = PngToIcon(stream.ToArray());
            using (var fs = new FileStream(filePath, FileMode.Create))
            {
                fs.Write(buffer, 0, buffer.Length);
            }
        }
    }

    private static void SaveToImage(FrameworkElement control, string filePath, string extension)
    {
        BitmapEncoder encoder;
        switch (extension)
        {
            case ".bmp":
                encoder = new BmpBitmapEncoder();
                break;

            case ".jpg":
            case ".jpeg":
                encoder = new JpegBitmapEncoder();
                break;

            case ".png":
                encoder = new PngBitmapEncoder();
                break;

            case ".gif":
                encoder = new GifBitmapEncoder();
                break;

            case ".tif":
            case ".tiff":
                encoder = new TiffBitmapEncoder();
                break;

            case ".wdp":
                encoder = new WmpBitmapEncoder();
                break;

            default:
                encoder = new PngBitmapEncoder();
                break;
        }

        if (extension != ".png")
        {
            SetAppropriateBackground(control, true);
        }

        var rect   = new Rect(control.RenderSize);
        var visual = new DrawingVisual();
        using (var dc = visual.RenderOpen())
        {
            dc.DrawRectangle(new VisualBrush(control), null, rect);
        }

        var bitmap = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
        bitmap.Render(visual);
        bitmap.Freeze();

        if (extension != ".png")
        {
            SetAppropriateBackground(control, false);
        }


        encoder.Frames.Add(BitmapFrame.Create(bitmap));

        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            encoder.Save(stream);
        }
    }

    private static void SetAppropriateBackground(FrameworkElement control, bool setBackground)
    {
        var grid = (Grid)control;
        grid.Background = setBackground ? Brushes.White : Brushes.Transparent;
        grid.UpdateLayout();
    }

#region Png 保存为 ico

    /// <summary>
    /// Png 保存为 ico
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    private static byte[] PngToIcon(byte[] data)
    {
        Image image;
        using (var stream = new MemoryStream(data))
        {
            image = Image.FromStream(stream);
        }

        using (var stream2 = new MemoryStream())
        {
            stream2.WriteByte(0);
            stream2.WriteByte(0);
            stream2.WriteByte(1);
            stream2.WriteByte(0);
            stream2.WriteByte(1);
            stream2.WriteByte(0);
            stream2.WriteByte((byte)image.Width);
            stream2.WriteByte((byte)image.Height);
            stream2.WriteByte(0);
            stream2.WriteByte(0);
            stream2.WriteByte(1);
            stream2.WriteByte(0);
            byte[] buffer = IntToLittle2(Image.GetPixelFormatSize(image.PixelFormat));
            stream2.Write(buffer, 0, 2);
            byte[] buffer3 = IntToLittle4(data.Length);
            stream2.Write(buffer3, 0, 4);
            stream2.WriteByte(0x16);
            stream2.WriteByte(0);
            stream2.WriteByte(0);
            stream2.WriteByte(0);
            stream2.Write(data, 0, data.Length);
            return stream2.ToArray();
        }
    }

    private static byte[] IntToLittle2(int input)
    {
        return new[] {
            ((byte)input), ((byte)((input >> 8) & 0xff))
        };
    }

    private static byte[] IntToLittle4(int input)
    {
        return new[] {
            (byte)input, (byte)((input >> 8) & 0xff), (byte)((input >> 0x10) & 0xff), (byte)((input >> 0x18) & 0xff)
        };
    }

#endregion

#endregion
}